package com.xzcode.jdbclink.core.sql;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import com.xzcode.jdbclink.core.JdbcLinkConfig;
import com.xzcode.jdbclink.core.entity.EntityFieldInfo;
import com.xzcode.jdbclink.core.entity.EntityInfo;
import com.xzcode.jdbclink.core.entity.IEntity;
import com.xzcode.jdbclink.core.exception.JdbcLinkRuntimeException;
import com.xzcode.jdbclink.core.util.ShowSqlUtil;

public class BatchInsert {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(BatchInsert.class);
	
	protected JdbcLinkConfig config;
	
	public BatchInsert(JdbcLinkConfig config) {
		this.config = config;
	}
	
	/**
	 * 插入数据
	 * @param record 实体对象
	 * @param autoGeneratedKeys 是否注入自增序列id
	 * @return
	 * @throws Exception
	 * 
	 * @author zai
	 * 2017-06-12
	 */
	public int batchInsert(List<IEntity> entities, boolean autoGeneratedKeys) {
		if (entities == null || entities.size() == 0) {
			return 0;
		}
		
		StringBuilder sql = config.getStringBuilderPool().get();
		StringBuilder valuesSql = config.getStringBuilderPool().get();
		try {
			
			IEntity entity = entities.get(0);
			
			Class<?> clazz = entity.getClass();
			
			EntityInfo entityInfo = config.getEntityInfoCache().getEntityInfo(clazz);
			
			
			
			sql.append(" insert into ").append(entityInfo.getTable());
			sql.append(" ( ");
			valuesSql.append("( ");
			
			List<EntityFieldInfo> fieldInfos = entityInfo.getFieldInfos();
			int fieldInfosSize = fieldInfos.size();
			
			for (int i = 0; i < fieldInfosSize; i++) {
				sql.append(fieldInfos.get(i).getColumn()).append(",");
				valuesSql.append("?,");
			}
			
			
			sql.setLength(sql.length() - 1);
			
			sql.append(" ) ").append(" values ");
			
			valuesSql.setLength(valuesSql.length() - 1);
			valuesSql.append(" ),");
			
			sql.append(valuesSql.toString());
			
			valuesSql.setLength(0);
			
			
			sql.setLength(sql.length() - 1);
			
			String sqlStr = sql.toString();
			
			
			
			PreparedStatementCreator statement = new PreparedStatementCreator() {
				
				@Override
				public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
					PreparedStatement prepareStatement = con.prepareStatement(sqlStr, Statement.RETURN_GENERATED_KEYS);
					try {
						Field field = null;
						for (IEntity rec : entities) {
							for (int i = 1; i <= fieldInfosSize; i++) {
								field = fieldInfos.get(i).getField();
									prepareStatement.setObject(i, field.get(rec));
								
								field.setAccessible(true);
							}
							prepareStatement.addBatch();
						}
						
						
						if (LOGGER.isDebugEnabled()) {
							StringBuilder sb = new StringBuilder();
							for (IEntity rec : entities) {
								sb.append("[");
								for (int i = 1; i <= fieldInfosSize; i++) {
									field = fieldInfos.get(i).getField();
									sb.append(field.get(rec)).append(",");
								}
								sb.setLength(sb.length() - 1);
								sb.append("]");
								sb.append("\n");
							}
							ShowSqlUtil.debugSqlAndParams(sqlStr, sb.toString());
						}
						
					} catch (Exception e) {
						throw new JdbcLinkRuntimeException(e);
					}
					
					return prepareStatement;
				}
			};
						
			//注入自增id
			if (autoGeneratedKeys) {
				
				GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
				int result = this.config.getJdbcTemplate().update(statement, keyHolder);
				
				//获取自增序列
				Long uid = keyHolder.getKey().longValue();
				
				//注入uid
				Field idField = entityInfo.getPrimaryKeyFieldInfo().getField();
				
				Class<?> idClass = entityInfo.getPrimaryKeyFieldInfo().getFieldClass();
				
				if (idField != null) {
					
					idField.setAccessible(true);
					
					if (idClass == Integer.class) {
						idField.set(entity, uid.intValue());
					}else {
						idField.set(entity, uid);						
					}
				}
				
				return result;
				
			}else{
				return this.config.getJdbcTemplate().update(statement);
			}
		
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			config.getStringBuilderPool().returnOject(valuesSql);
			
			config.getStringBuilderPool().returnOject(sql);
		}
		
	}

}
